// Copyright 2020 Joan Pablo Jimenez Milian. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

import 'package:bruno/bruno.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';

/// This is a convenience widget that wraps a [Switch] widget in a
/// [ReactiveSwitch].
///
/// Can optionally provide a [formControl] to bind this widget to a control.
///
/// Can optionally provide a [formControlName] to bind this ReactiveFormField
/// to a [FormControl].
///
/// Must provide one of the arguments [formControl] or a [formControlName],
/// but not both at the same time.
///
/// For documentation about the various parameters, see the [Switch] class
/// and [Switch], the constructor.
class ReactiveBrnSwitch extends ReactiveFormField<bool, bool> {
  /// Creates a [ReactiveSwitch] that wraps a material design switch.
  ///
  /// Can optionally provide a [formControl] to bind this widget to a control.
  ///
  /// Can optionally provide a [formControlName] to bind this ReactiveFormField
  /// to a [FormControl].
  ///
  /// Must provide one of the arguments [formControl] or a [formControlName],
  /// but not both at the same time.
  ///
  /// For documentation about the various parameters, see the [Switch] class
  /// and [Switch], the constructor.
  ReactiveBrnSwitch({
    Key? key,
    String? formControlName,
    FormControl<bool>? formControl,
    ReactiveFormFieldCallback<bool>? onChanged,

    /// 录入项的唯一标识，主要用于录入类型页面框架中
    String? label,

    /// 录入项标题
    required String title,

    /// 录入项子标题
    String? subTitle,

    /// 录入项提示（问号图标&文案） 用户点击时触发onTip回调。
    /// 1. 若赋值为 空字符串（""）时仅展示"问号"图标，
    /// 2. 若赋值为非空字符串时 展示"问号图标&文案"，
    /// 3. 若不赋值或赋值为null时 不显示提示项
    /// 默认值为 3
    String? tipLabel,

    /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类
    String prefixIconType = BrnPrefixIconType.normal,

    /// 录入项错误提示
    String error = '',

    /// 录入项是否为必填项（展示*图标） 默认为 false 不必填
    bool isRequire = false,

    /// 录入项 是否可编辑
    bool isEdit = true,

    /// 点击"+"图标回调
    final VoidCallback? onAddTap,

    /// 点击"-"图标回调
    final VoidCallback? onRemoveTap,

    /// 点击"？"图标回调
    final VoidCallback? onTip,

    /// 特有字段
    final bool value = false,

    /// 背景色
    final Color? backgroundColor,

    /// form配置
    BrnFormItemConfig? themeData,
  }) : super(
          key: key,
          formControl: formControl,
          formControlName: formControlName,
          builder: (field) {
            final state = field as _ReactiveSwitchState<bool, bool>;

            return BrnSwitchFormItem(
              value: field.value ?? false,
              label: label,
              title: title,
              subTitle: subTitle,
              tipLabel: tipLabel,
              prefixIconType: prefixIconType,
              error: error,
              isRequire: isRequire,
              isEdit: isEdit,
              backgroundColor: backgroundColor,
              onAddTap: onAddTap,
              onRemoveTap: onRemoveTap,
              themeData: themeData,
              onTip: onTip,
              onChanged: field.control.enabled
                  ? (oldValue, newValue) {
                      field.didChange(newValue);
                      onChanged?.call(field.control);
                    }
                  : null,
            );
          },
        );

  @override
  ReactiveFormFieldState<bool, bool> createState() =>
      _ReactiveSwitchState<bool, bool>();
}

class _ReactiveSwitchState<T, V> extends ReactiveFormFieldState<T, V> {
  FocusNode? _focusNode;
  late FocusController _focusController;

  FocusNode get focusNode => _focusNode ?? _focusController.focusNode;

  @override
  void subscribeControl() {
    _registerFocusController(FocusController());
    super.subscribeControl();
  }

  @override
  void unsubscribeControl() {
    _unregisterFocusController();
    super.unsubscribeControl();
  }

  void _registerFocusController(FocusController focusController) {
    _focusController = focusController;
    control.registerFocusController(focusController);
  }

  void _unregisterFocusController() {
    control.unregisterFocusController(_focusController);
    _focusController.dispose();
  }

  void _setFocusNode(FocusNode? focusNode) {
    if (_focusNode != focusNode) {
      _focusNode = focusNode;
      _unregisterFocusController();
      _registerFocusController(FocusController(focusNode: _focusNode));
    }
  }
}
